Skip to content

Vite 工程实践(创建项目 · 配置文件 · 环境变量)

建议阅读顺序:先 脚手架与项目创建,再 vite.config,最后 .envimport.meta.env。配置索引以官方为准:Config Reference · Env Variables


第一部分:创建项目

注意事项

Vite 需要 Node.js 版本 20.19+, 22.12+。然而,有些模板需要依赖更高的 Node 版本才能正常运行,当你的包管理器发出警告时,请注意升级你的 Node 版本。

shell
# npm
npm create vite@latest

# yarn
yarn create vite

# pnpm
pnpm create vite

第二部分:配置文件

Vite 配置文件(通常是 vite.config.js 或 vite.config.ts)是构建和开发过程的核心,它使用 ES 模块语法(因为 Vite 本身基于原生 ES 模块),并通过导出一个配置对象或函数来定制 Vite 的行为。

基本形式(对象语法)

js
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  // 核心配置项
  plugins: [vue()], // 插件配置
  server: {
    port: 3000, // 开发服务器端口
  },
  build: {
    outDir: 'dist', // 构建输出目录
  },
});

函数语法(支持动态配置)

js
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import fs from 'fs';

export default defineConfig(({ command, mode }) => {
  // command: 'serve'(开发环境)或 'build'(构建环境)
  // mode: 运行模式(默认 'development' 或 'production',可通过 --mode 指定)

  const isProduction = mode === 'production';

  return {
    plugins: [vue()],
    server: {
      port: isProduction ? 8080 : 3000,
    },
    build: {
      minify: isProduction,
    },
  };
});

配置选项(八项)

1、plugins:扩展 Vite 的功能,例如处理 Vue/React 单文件组件、CSS 预处理器、静态资源等

  1. 常用插件
shell
@vitejs/plugin-vue:支持 Vue 3 单文件组件(.vue)。
@vitejs/plugin-vue-jsx:支持 Vue 3 JSX/TSX。
@vitejs/plugin-react:支持 React(自动处理 JSX、Fast Refresh)。
@vitejs/plugin-legacy:为旧浏览器提供兼容性支持(通过 Babel 转换)。
vite-plugin-svg-icons:处理 SVG 图标(例如将 SVG 转为组件)。
rollup-plugin-visualizer:构建体积分析工具。
  1. 示例
js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import legacy from '@vitejs/plugin-legacy';
import svgIcons from 'vite-plugin-svg-icons';
import path from 'path';

export default defineConfig({
  plugins: [
    vue(),
    legacy({
      targets: ['defaults', 'not IE 11'], // 兼容目标
    }),
    svgIcons({
      iconDirs: [path.resolve(process.cwd(), 'src/icons')], // SVG 图标目录
      symbolId: 'icon-[dir]-[name]', // 图标 ID 格式
    }),
  ],
});

2、server:配置开发服务器的行为(本地开发时使用)

  1. 子配置
shell
# 子配置
port:开发服务器端口(默认 5173)。
open:是否自动在浏览器中打开项目(默认 false)。
host:主机名(默认 'localhost',设置为 '0.0.0.0' 可局域网访问)。
proxy:配置跨域代理(解决开发时的跨域请求问题)。
hmr:热模块替换(HMR)配置(默认开启)。
https:是否启用 HTTPS(默认 false,可通过 cert key 指定证书)。
  1. 示例
js
export default defineConfig({
  server: {
    port: 3000,
    open: true,
    host: '0.0.0.0',
    proxy: {
      // 代理 /api 请求到后端服务
      '/api': {
        target: 'http://localhost:8080', // 后端接口地址
        changeOrigin: true, // 改变源(避免 CORS 问题)
        rewrite: (path) => path.replace(/^\/api/, ''), // 重写路径(去掉 /api 前缀)
      },
    },
    hmr: {
      overlay: false, // 关闭 HMR 错误覆盖层
    },
    https: {
      cert: fs.readFileSync(path.resolve(__dirname, 'cert.pem')),
      key: fs.readFileSync(path.resolve(__dirname, 'key.pem')),
    },
  },
});

3、build:配置生产环境构建的行为

  1. 子配置
shell
outDir:构建输出目录(默认 dist)。
assetsDir:静态资源(JS、CSS、图片等)的输出目录(默认 assets)。
assetsInlineLimit:小于该大小的静态资源会被内联为 Base64(默认 4096 字节,即 4KB)。
minify:构建时是否压缩代码(默认 'esbuild',可选 'terser' false)。
sourcemap:是否生成 SourceMap(默认 false,生产环境建议关闭以减小体积)。
rollupOptions:自定义 Rollup 配置(Vite 底层使用 Rollup 进行构建)。
chunkSizeWarningLimit:触发代码分割警告的 chunk 大小(默认 500KB)。
lib:构建为库模式(适用于开发组件库或工具库)。
  1. 示例
js
export default defineConfig({
  build: {
    outDir: 'dist',
    assetsDir: 'static',
    assetsInlineLimit: 8192, // 8KB 以下的资源内联
    minify: 'esbuild', // 使用 esbuild 压缩(比 terser 更快)
    sourcemap: false,
    rollupOptions: {
      // 自定义输出文件名
      output: {
        entryFileNames: 'js/[name].[hash].js',
        chunkFileNames: 'js/[name].[hash].chunk.js',
        assetFileNames: '[ext]/[name].[hash].[ext]',
      },
      // 排除不需要打包的依赖(例如通过 CDN 引入)
      external: ['vue'],
    },
    chunkSizeWarningLimit: 1000, // 1MB 触发警告
  },
});

4、resolve:配置模块解析规则(例如路径别名、文件后缀省略等)

  1. 子配置
shell
alias:路径别名(简化导入路径)。
extensions:导入时可省略的文件后缀(默认 ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json'])。
conditions:解析包的 exports 字段时的条件(默认 ['import', 'module', 'browser', 'default'])。
mainFields:解析包的入口文件时的字段优先级(默认 ['module', 'jsnext:main', 'jsmain'])。
  1. 示例
js
import path from 'path';

export default defineConfig({
  resolve: {
    // 路径别名:@ 指向 src 目录
    alias: {
      '@': path.resolve(__dirname, 'src'),
      '@components': path.resolve(__dirname, 'src/components'),
    },
    // 导入时可省略的后缀(新增 .vue 和 .scss)
    extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue', '.scss'],
  },
});

5、css:配置 CSS 相关的处理规则(例如预处理器、CSS Modules、PostCSS 等)

  1. 子配置
shell
modules:CSS Modules 配置(默认 {},例如自定义类名格式)。
preprocessorOptions:CSS 预处理器(Sass/Less/Stylus)的选项(例如全局变量、导入路径)。
devSourcemap:开发环境是否生成 CSS SourceMap(默认 false)。
postcss:PostCSS 配置(例如 autoprefixer、cssnano 等)。
  1. 示例
js
export default defineConfig({
  css: {
    // CSS Modules 配置:类名格式为 [name]__[local]--[hash]
    modules: {
      localsConvention: 'camelCaseOnly', // 仅支持驼峰命名(例如 .btn-primary 转为 btnPrimary)
      generateScopedName: '[name]__[local]--[hash:base64:5]',
    },
    // Sass 预处理器配置:全局导入变量文件
    preprocessorOptions: {
      scss: {
        additionalData: `@import "@/styles/variables.scss";`, // 全局导入变量
      },
      less: {
        globalVars: {
          primaryColor: '#1890ff', // Less 全局变量
        },
      },
    },
    // 开发环境生成 CSS SourceMap
    devSourcemap: true,
    // PostCSS 配置(也可通过 postcss.config.js 文件配置)
    postcss: {
      plugins: [
        require('autoprefixer')({
          overrideBrowserslist: ['last 2 versions', '> 1%'],
        }),
      ],
    },
  },
});

6、optimizeDeps:配置依赖预构建规则(Vite 开发时会将第三方依赖预构建为 ES 模块,以提高加载速度)

  1. 子配置
shell
include:强制预构建的依赖(例如某些未被 Vite 自动检测到的依赖)。
exclude:排除不需要预构建的依赖(例如原生 ES 模块的依赖)。
esbuildOptions:传递给 esbuild 的选项(例如目标环境、压缩配置)。
force:是否强制重新预构建(默认 false,可通过 vite --force 命令触发)。
  1. 示例
js
export default defineConfig({
  optimizeDeps: {
    // 强制预构建 lodash-es 和 moment
    include: ['lodash-es', 'moment'],
    // 排除不需要预构建的依赖(例如已是 ES 模块的包)
    exclude: ['vue-demi'],
    // esbuild 选项:目标环境为 ES2020
    esbuildOptions: {
      target: 'es2020',
    },
  },
});

7、define:定义全局常量(在代码中可直接使用,无需导入)

值必须是字符串(如果是布尔值或数字,需要用 JSON.stringify 转换)。

js
export default defineConfig({
  define: {
    // 定义环境变量(也可通过 .env 文件配置,优先级:.env.local > .env.development > .env)
    'import.meta.env.VITE_APP_TITLE': JSON.stringify('My Vite App'),
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
    '__APP_VERSION__': JSON.stringify('1.0.0'),
  },
});

8、preview:配置预览服务器的行为(构建后通过 vite preview 预览生产环境文件)

js
export default defineConfig({
  preview: {
    port: 8080,
    open: true,
    host: '0.0.0.0',
  },
});

异步配置

配置文件可导出一个异步函数,支持动态获取配置(例如从接口或文件读取配置)

js
export default defineConfig(async ({ mode }) => {
  // 异步获取配置
  const remoteConfig = await fetch('https://api.example.com/vite-config').then(res => res.json());

  return {
    server: {
      port: remoteConfig.port || 3000,
    },
    define: {
      'VITE_REMOTE_CONFIG': JSON.stringify(remoteConfig),
    },
  };
});

多环境配置

通过 mode 参数区分不同环境(例如开发、测试、生产),并加载对应的配置。

js
// vite.config.js
import { defineConfig, loadEnv } from 'vite';
import baseConfig from './vite.base.config'; // 基础配置
import devConfig from './vite.dev.config'; // 开发环境配置
import prodConfig from './vite.prod.config'; // 生产环境配置

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd());
  const isDev = mode === 'development';
  const isProd = mode === 'production';

  // 合并基础配置和环境特定配置
  return {
    ...baseConfig,
    ...(isDev ? devConfig : isProd ? prodConfig : {}),
    define: {
      ...baseConfig.define,
      'import.meta.env': JSON.stringify(env),
    },
  };
});

常用配置示例(完整模板)

js
// vite.config.js
import { defineConfig, loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import legacy from '@vitejs/plugin-legacy';
import svgIcons from 'vite-plugin-svg-icons';
import path from 'path';
import fs from 'fs';

// 路径解析函数
const resolve = (dir) => path.resolve(__dirname, dir);

export default defineConfig(({ command, mode }) => {
  const env = loadEnv(mode, process.cwd());
  const isDev = command === 'serve';
  const isProd = command === 'build';

  return {
    // 基础路径(生产环境部署时的基础 URL)
    base: isProd ? env.VITE_BASE_URL || '/' : '/',

    // 插件配置
    plugins: [
      vue(),
      vueJsx(),
      // 生产环境启用 legacy 插件
      isProd &&
        legacy({
          targets: ['defaults', 'not IE 11'],
        }),
      svgIcons({
        iconDirs: [resolve('src/icons')],
        symbolId: 'icon-[dir]-[name]',
      }),
    ].filter(Boolean), // 过滤掉 false 的插件

    // 开发服务器配置
    server: {
      port: Number(env.VITE_DEV_PORT) || 3000,
      open: env.VITE_OPEN_BROWSER === 'true',
      host: '0.0.0.0',
      proxy: {
        '/api': {
          target: env.VITE_API_BASE_URL,
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/api/, ''),
        },
      },
      hmr: {
        overlay: env.VITE_HMR_OVERLAY === 'true',
      },
    },

    // 构建配置
    build: {
      outDir: env.VITE_BUILD_OUT_DIR || 'dist',
      assetsDir: 'static',
      assetsInlineLimit: 8192,
      minify: 'esbuild',
      sourcemap: env.VITE_BUILD_SOURCEMAP === 'true',
      rollupOptions: {
        output: {
          entryFileNames: 'js/[name].[hash].js',
          chunkFileNames: 'js/[name].[hash].chunk.js',
          assetFileNames: '[ext]/[name].[hash].[ext]',
          // 手动分割代码块
          manualChunks: {
            vue: ['vue', 'vue-router', 'pinia'],
            ui: ['element-plus'],
          },
        },
        // 排除外部依赖(通过 CDN 引入)
        external: env.VITE_EXTERNAL_DEPENDENCIES
          ? env.VITE_EXTERNAL_DEPENDENCIES.split(',')
          : [],
      },
      chunkSizeWarningLimit: 1000,
    },

    // 模块解析配置
    resolve: {
      alias: {
        '@': resolve('src'),
        '@components': resolve('src/components'),
        '@views': resolve('src/views'),
        '@utils': resolve('src/utils'),
        '@styles': resolve('src/styles'),
      },
      extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue', '.scss'],
    },

    // CSS 配置
    css: {
      modules: {
        localsConvention: 'camelCaseOnly',
        generateScopedName: isDev ? '[name]__[local]' : '[name]__[local]--[hash:base64:5]',
      },
      preprocessorOptions: {
        scss: {
          additionalData: `@import "@/styles/variables.scss"; @import "@/styles/mixins.scss";`,
        },
      },
      devSourcemap: isDev,
      postcss: {
        plugins: [
          require('autoprefixer')({
            overrideBrowserslist: ['last 2 versions', '> 1%', 'iOS >= 10', 'Android >= 7'],
          }),
          // 生产环境启用 cssnano 压缩
          isProd &&
            require('cssnano')({
              preset: ['default', { discardComments: { removeAll: true } }],
            }),
        ].filter(Boolean),
      },
    },

    // 依赖预构建配置
    optimizeDeps: {
      include: ['lodash-es', 'moment', 'element-plus/es/components/*/style/css'],
      esbuildOptions: {
        target: 'es2020',
      },
    },

    // 全局常量定义
    define: {
      'import.meta.env': JSON.stringify(env),
      'process.env.NODE_ENV': JSON.stringify(mode),
      '__APP_VERSION__': JSON.stringify(require('./package.json').version),
    },

    // 预览服务器配置
    preview: {
      port: Number(env.VITE_PREVIEW_PORT) || 8080,
      open: env.VITE_OPEN_BROWSER === 'true',
      host: '0.0.0.0',
    },
  };
});

第三部分:环境变量

作用

shell
区分环境:为开发、测试、生产等不同环境提供不同的配置
保护敏感信息:将 API 密钥、数据库密码等敏感信息存储在环境变量中,避免直接暴露在代码中
提高可维护性:集中管理配置,便于统一修改和维护

vite 内置的环境变量

shell
import.meta.env.MODE:当前的环境模式(如 development、production、test)。
import.meta.env.BASE_URL:项目的基础 URL,由 vite.config.ts 中的 base 配置决定。
import.meta.env.PROD:是否为生产环境(boolean 类型)。
import.meta.env.DEV:是否为开发环境(boolean 类型,与 PROD 相反)。
import.meta.env.SSR:是否为服务端渲染环境(boolean 类型)。

配置规则

shell
# 文件命名规则
 文件名            说明                               加载时机
.env            所有环境通用的基础配置                 所有环境都会加载
.env.local        所有环境通用的本地配置(不提交到 Git)     所有环境都会加载,但会被更具体的环境文件覆盖
.env.[mode]        特定环境的配置(如 .env.development) 对应模式下加载
.env.[mode].local  特定环境的本地配置(不提交到 Git)         对应模式下加载,优先级最高
## 加载优先级(范围越小越优先)
.env.[mode].local > .env.[mode] > .env.local > .env

# 内容定义规则
环境变量文件中,每行只能定义一个变量,格式为 KEY=VALUE(等号前后不要有空格),比如:VITE_APP_TITLE=My App
自定义环境变量要以 VITE_开头,比如:VITE_API_BASE_URL=http://localhost:3000/api
环境变量的值没有数据类型的说法,只是字符串,比如:定义 VITE_IS=true,在获取后的结果是 "true" 字符串


# 注释规则
井号注释要独占一行,不要在变量后面加井号注释(概率会解析出错)

# 注意
[mode] 可以是 development、production、test 或自定义的模式名称
.local 后缀的文件应该被添加到 .gitignore 中,避免敏感信息泄露。

获取环境变量

  1. 在 vue、react、js 文件中获取(通过 import.meta.env.变量名 获取)
js
const title = import.meta.env.VITE_APP_TITLE
  1. 在 vite.config.js 中获取
js
import { defineConfig, loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue';

// https://vitejs.dev/config/
export default defineConfig(({ command, mode }) => {
  // 根据当前工作目录中的 `mode` 加载 .env 文件
  // 第三个参数 '' 表示加载所有环境变量,而不仅仅是 VITE_ 开头的
  const env = loadEnv(mode, process.cwd(), '');

  // 现在你可以通过 env 对象访问所有环境变量了
  console.log('当前环境模式:', mode);
  console.log('API 基础地址:', env.VITE_API_BASE_URL);
  console.log('是否生成 Source Map:', env.GENERATE_SOURCEMAP);

  return {
    plugins: [vue()],
    
    // 示例 1: 根据环境变量配置开发服务器代理
    server: {
      proxy: {
        // 只有开发环境才配置代理
        '/api': {
          // 这里使用从环境文件中读取的地址
          target: env.VITE_API_BASE_URL,
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/api/, '')
        },
      }
    },

    // 示例 2: 根据环境变量配置构建选项
    build: {
      // 从环境变量读取是否生成 sourcemap
      sourcemap: env.GENERATE_SOURCEMAP === 'true',
      
      // 根据环境不同,设置不同的输出目录
      outDir: mode === 'production' ? 'dist' : 'dist-dev'
    },

    // 示例 3: 在插件配置中使用环境变量
    define: {
      // 虽然 Vite 会自动注入 VITE_* 变量,但如果你有特殊需求,也可以手动定义
      // 注意:这里需要用 JSON.stringify 来确保它被当作字符串注入
      __APP_VERSION__: JSON.stringify(env.npm_package_version), // 读取 package.json 的版本号
    }
  };
});